package com.jiangxjsy.core.redis.impl;

import com.jiangxjsy.core.constant.RedisCacheConstant;
import com.jiangxjsy.core.redis.Redis;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * wukong-crm-master
 * 蒋胜宇
 * 2025/6/2 10:06
 */

@Service
public class RedisImpl implements Redis {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 添加 key 前缀
     *
     * @param key key
     * @return 完整的 key
     */
    private String appendKeyPrefix(Object key) {
        String keyStr;

        if (key instanceof String) {
            keyStr = (String) key;
        } else {
            keyStr = key.toString();
        }

        return RedisCacheConstant.REDIS_KEY_PREFIX + keyStr;
    }

    /**
     * 根据多个 key 删除 Redis 中的缓存
     *
     * @param keys keys，允许多个
     */
    @Override
    public void delete(Object... keys) {
        List<String> keyList = new ArrayList<>();
        for (Object key : keys) {
            keyList.add(appendKeyPrefix(key));
        }
        Long ignore = redisTemplate.delete(keyList);
    }

    /**
     * 根据多个 key 删除 Redis 中的缓存
     *
     * @param keys keys，允许多个
     */
    @Override
    public void delete(String... keys) {
        delete(((Object[]) keys));
    }

    /**
     * 获取 key 的剩余时间，其类似于命令 ttl key
     *
     * @param key key
     * @return 剩余时间，单位：秒
     */
    @Override
    public Long ttl(Object key) {
        return redisTemplate.getExpire(appendKeyPrefix(key));
    }

    /**
     * 获取 key 的剩余时间，其类似于命令 ttl key
     *
     * @param key key
     * @return 剩余时间，单位：秒
     */
    @Override
    public Long ttl(String key) {
        return ttl((Object) key);
    }

    /**
     * 设置 key 的过期时间
     *
     * @param key key
     * @param timeout 过期时间，单位：秒
     */
    @Override
    public void expire(Object key, Integer timeout) {
        Boolean ignore = redisTemplate.expire(appendKeyPrefix(key), timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置 key 的过期时间
     *
     * @param key key
     * @param timeout 过期时间，单位：秒
     */
    @Override
    public void expire(String key, Integer timeout) {
        expire((Object) key, timeout);
    }

    /**
     * 设置 key 的过期时间
     *
     * @param key key
     * @param timeout 过期时间
     * @param timeUnit 时间单位
     */
    @Override
    public void expire(Object key, Integer timeout, TimeUnit timeUnit) {
        Boolean ignore = redisTemplate.expire(appendKeyPrefix(key), timeout, timeUnit);
    }

    /**
     * 设置 key 的过期时间
     *
     * @param key key
     * @param timeout 过期时间
     * @param timeUnit 时间单位
     */
    @Override
    public void expire(String key, Integer timeout, TimeUnit timeUnit) {
        expire((Object) key, timeout, timeUnit);
    }

    /**
     * 移除 key 的过期时间
     *
     * @param key key
     */
    @Override
    public void persist(Object key) {
        Boolean ignore = redisTemplate.persist(appendKeyPrefix(key));
    }

    /**
     * 移除 key 的过期时间
     *
     * @param key key
     */
    @Override
    public void persist(String key) {
        persist((Object) key);
    }

    /**
     * 判断 key 是否存在
     *
     * @param key key
     * @return 存在与否
     */
    @Override
    public Boolean hasKey(Object key) {
        Boolean exists = redisTemplate.hasKey(appendKeyPrefix(key));
        return exists != null ? exists : false;
    }

    /**
     * 判断 key 是否存在
     *
     * @param key key
     * @return 存在与否
     */
    @Override
    public Boolean hasKey(String key) {
        return hasKey((Object) key);
    }

    /**
     * 获取 key 所储存的值的类型
     *
     * @param key key
     * @return 类型
     */
    @Override
    public DataType type(Object key) {
        return redisTemplate.type(appendKeyPrefix(key));
    }

    /**
     * 获取 key 所储存的值的类型
     *
     * @param key key
     * @return 类型
     */
    @Override
    public DataType type(String key) {
        return type((Object) key);
    }

    /**
     * 设置 key 的值
     *
     * @param key key
     * @param value value
     */
    @Override
    public void set(Object key, Object value) {
        redisTemplate.opsForValue().set(appendKeyPrefix(key), value);
    }

    /**
     * 设置 key 的值
     *
     * @param key key
     * @param value value
     */
    @Override
    public void set(String key, Object value) {
        set((Object) key, value);
    }

    /**
     * 设置 key 的值，并设置过期时间
     *
     * @param key key
     * @param value value
     * @param timeout 过期时间，单位：秒
     */
    @Override
    public void setEx(Object key, Object value, Integer timeout) {
        redisTemplate.opsForValue().set(appendKeyPrefix(key), value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置 key 的值，并设置过期时间
     *
     * @param key key
     * @param value value
     * @param timeout 过期时间，单位：秒
     */
    @Override
    public void setEx(String key, Object value, Integer timeout) {
        setEx((Object) key, value, timeout);
    }

    /**
     * 设置 key 的值，并设置过期时间
     *
     * @param key key
     * @param value value
     * @param timeout 过期时间
     * @param timeUnit 时间单位
     */
    @Override
    public void setEx(Object key, Object value, Integer timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(appendKeyPrefix(key), value, timeout, timeUnit);
    }

    /**
     * 添加 key 的值，并设置过期时间
     *
     * @param key key
     * @param value value
     * @param timeout 过期时间
     * @param timeUnit 时间单位
     */
    @Override
    public void setEx(String key, Object value, Integer timeout, TimeUnit timeUnit) {
        setEx((Object) key, value, timeout, timeUnit);
    }

    /**
     * 设置 key 的值，如果 key 已经存在，则返回 false
     *
     * @param key key
     * @param value value
     * @return 添加成功与否
     */
    @Override
    public Boolean setNx(Object key, Object value) {
        return redisTemplate.opsForValue().setIfAbsent(appendKeyPrefix(key), value);
    }

    /**
     * 设置 key 的值，如果 key 已经存在，则返回 false
     *
     * @param key key
     * @param value value
     * @return 添加成功与否
     */
    @Override
    public Boolean setNx(String key, Object value) {
        return setNx((Object) key, value);
    }

    /**
     * 设置 key 的值，并设置过期时间，如果 key 已经存在，则返回 false
     *
     * @param key key
     * @param value value
     * @param timeout 过期时间，单位：秒
     * @return 添加成功与否
     */
    @Override
    public Boolean setNx(Object key, Object value, Integer timeout) {
        return redisTemplate.opsForValue().setIfAbsent(appendKeyPrefix(key), value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置 key 的值，并设置过期时间，如果 key 已经存在，则返回 false
     *
     * @param key key
     * @param value value
     * @param timeout 过期时间，单位：秒
     * @return 添加成功与否
     */
    @Override
    public Boolean setNx(String key, Object value, Integer timeout) {
        return setNx((Object) key, value, timeout);
    }

    /**
     * 设置 key 的值，并设置过期时间，如果 key 已经存在，则返回 false
     *
     * @param key key
     * @param value value
     * @param timeout 过期时间
     * @param timeUnit 时间单位
     * @return 添加成功与否
     */
    @Override
    public Boolean setNx(Object key, Object value, Integer timeout, TimeUnit timeUnit) {
        return redisTemplate.opsForValue().setIfAbsent(appendKeyPrefix(key), value, timeout, timeUnit);
    }

    /**
     * 设置 key 的值，并设置过期时间，如果 key 已经存在，则返回 false
     *
     * @param key key
     * @param value value
     * @param timeout 过期时间
     * @param timeUnit 时间单位
     * @return 添加成功与否
     */
    @Override
    public Boolean setNx(String key, Object value, Integer timeout, TimeUnit timeUnit) {
        return setNx((Object) key, value, timeout, timeUnit);
    }

    /**
     * 批量设置 key 的值
     *
     * @param map map
     */
    @Override
    public void multiSet(Map<String, Object> map) {
        for (String key : map.keySet()) {
            Object value = map.remove(key);
            map.put(appendKeyPrefix(key), value);
        }
        redisTemplate.opsForValue().multiSet(map);
    }

    /**
     * 批量设置 key 的值，如果 key 已经存在，则返回 false
     *
     * @param map map
     * @return 添加成功与否
     */
    @Override
    public Boolean multiSetNx(Map<String, Object> map) {
        for (String key : map.keySet()) {
            Object value = map.remove(key);
            map.put(appendKeyPrefix(key), value);
        }
        return redisTemplate.opsForValue().multiSetIfAbsent(map);
    }

    /**
     * 获取 key 的值
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T get(Class<T> clazz, Object key) {
        Object value = redisTemplate.opsForValue().get(appendKeyPrefix(key));
        if (value == null || !clazz.isAssignableFrom(value.getClass())) {
            return null;
        }
        return clazz.cast(value);
    }

    /**
     * 获取 key 的值
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T get(Class<T> clazz, String key) {
        return get(clazz, (Object) key);
    }

    /**
     * 获取 key 的值
     *
     * @param key key
     * @return value
     */
    @Override
    public Object get(Object key) {
        return redisTemplate.opsForValue().get(appendKeyPrefix(key));
    }

    /**
     * 获取 key 的值
     *
     * @param key key
     * @return value
     */
    @Override
    public Object get(String key) {
        return get((Object) key);
    }

    /**
     * 批量获取 key 的值
     *
     * @param clazz 泛型的类对象
     * @param keys keys
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> List<T> multiGet(Class<T> clazz, Object... keys) {
        List<String> keysList = new ArrayList<>();
        for (Object key : keys) {
            keysList.add(appendKeyPrefix(key));
        }
        List<Object> values = redisTemplate.opsForValue().multiGet(keysList);

         if (values != null) {
            List<T> result = new ArrayList<>();
            for (Object value : values) {
                if (value == null || !clazz.isAssignableFrom(value.getClass())) {
                    return null;
                }
                result.add(clazz.cast(value));
            }
            return result;
        }
        return null;
    }

    /**
     * 批量获取 key 的值
     *
     * @param keys keys
     * @return value
     */
    @Override
    public List<Object> multiGet(Object... keys) {
        List<String> keysList = new ArrayList<>();
        for (Object key : keys) {
            keysList.add(appendKeyPrefix(key));
        }
        return redisTemplate.opsForValue().multiGet(keysList);
    }

    /**
     * 追加 key 的值
     *
     * @param key key
     * @param value value 追加的值
     */
    @Override
    public void append(Object key, String value) {
        Integer ignore = redisTemplate.opsForValue().append(appendKeyPrefix(key), value);
    }

    /**
     * 追加 key 的值
     *
     * @param key key
     * @param value value 追加的值
     */
    @Override
    public void append(String key, String value) {
        append((Object) key, value);
    }

    /**
     * 删除 key 所存储的 hash 对象中的多个字段
     *
     * @param key key
     * @param fields fields
     */
    @Override
    public void hashDelete(Object key, Object... fields) {
        Long ignore = redisTemplate.opsForHash().delete(appendKeyPrefix(key), fields);
    }

    /**
     * 设置 key 所存储的 hash 对象中的字段值
     *
     * @param key key
     * @param field field
     * @param value value
     */
    @Override
    public void hashPut(Object key, Object field, Object value) {
        redisTemplate.opsForHash().put(appendKeyPrefix(key), field, value);
    }

    /**
     * 批量设置 key 所存储的 hash 对象中的字段值
     *
     * @param key key
     * @param map map
     */
    @Override
    public void hashPutAll(Object key, Map<Object, Object> map) {
        redisTemplate.opsForHash().putAll(appendKeyPrefix(key), map);
    }

    /**
     * 获取 key 所存储的整个 hash 对象
     *
     * @param key key
     * @return value
     */
    @Override
    public Map<Object, Object> hashEntries(Object key) {
        return redisTemplate.opsForHash().entries(appendKeyPrefix(key));
    }

    /**
     * 获取 key 所存储的 hash 对象中的所有字段的值
     *
     * @param key key
     * @return value
     */
    @Override
    public List<Object> hashValues(Object key) {
        return redisTemplate.opsForHash().values(appendKeyPrefix(key));
    }

    /**
     * 判断 key 所存储的 hash 对象中是否存在 field 字段
     * @param key key
     * @param field field
     * @return 存在与否
     */
    @Override
    public Boolean hashHasKey(Object key, Object field) {
        return redisTemplate.opsForHash().hasKey(appendKeyPrefix(key), field);
    }

    /**
     * 从左入栈
     * @param key key
     * @param value value
     */
    @Override
    public void listLeftPush(Object key, Object value) {
        redisTemplate.opsForList().leftPush(appendKeyPrefix(key), value);
    }

    /**
     * 从左入栈
     *
     * @param key key
     * @param value value
     */
    @Override
    public void listLeftPush(String key, Object value) {
        listLeftPush((Object) key, value);
    }

    /**
     * 从右入栈
     *
     * @param key key
     * @param value value
     */
    @Override
    public void listRightPush(Object key, Object value) {
        redisTemplate.opsForList().rightPush(appendKeyPrefix(key), value);
    }

    /**
     * 从右入栈
     *
     * @param key key
     * @param value value
     */
    @Override
    public void listRightPush(String key, Object value) {
        listRightPush((Object) key, value);
    }

    /**
     * 从左出栈
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T listLeftPop(Class<T> clazz, Object key) {
        Object value = redisTemplate.opsForList().leftPop(appendKeyPrefix(key));
        if (value == null || !clazz.isAssignableFrom(value.getClass())) {
            return null;
        }
        return clazz.cast(value);
    }

    /**
     * 从左出栈
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T listLeftPop(Class<T> clazz, String key) {
        return listLeftPop(clazz, (Object) key);
    }

    /**
     * 从左出栈
     *
     * @param key key
     * @return value
     */
    @Override
    public Object listLeftPop(Object key) {
        return redisTemplate.opsForList().leftPop(appendKeyPrefix(key));
    }

    /**
     * 从左出栈
     *
     * @param key key
     * @return value
     */
    @Override
    public Object listLeftPop(String key) {
        return listLeftPop((Object) key);
    }

    /**
     * 从右出栈
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T listRightPop(Class<T> clazz, Object key) {
        Object value = redisTemplate.opsForList().rightPop(appendKeyPrefix(key));
        if (value == null || !clazz.isAssignableFrom(value.getClass())) {
            return null;
        }
        return clazz.cast(value);
    }

    /**
     * 从右出栈
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T listRightPop(Class<T> clazz, String key) {
        return listRightPop(clazz, (Object) key);
    }

    /**
     * 从右出栈
     *
     * @param key key
     * @return value
     */
    @Override
    public Object listRightPop(Object key) {
        return redisTemplate.opsForList().rightPop(appendKeyPrefix(key));
    }

    /**
     * 从右出栈
     *
     * @param key key
     * @return value
     */
    @Override
    public Object listRightPop(String key) {
        return listRightPop((Object) key);
    }

    /**
     * 获取 key 所存储的 list 中指定索引的元素
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @param index 索引
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T listIndex(Class<T> clazz, Object key, int index) {
        Object value = redisTemplate.opsForList().index(appendKeyPrefix(key), index);
        if (value == null || !clazz.isAssignableFrom(value.getClass())) {
            return null;
        }
        return clazz.cast(value);
    }

    /**
     * 获取 key 所存储的 list 中指定索引的元素
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @param index 索引
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T listIndex(Class<T> clazz, String key, int index) {
        return listIndex(clazz, (Object) key, index);
    }

    /**
     * 获取 key 所存储的 list 中指定索引的元素
     *
     * @param key key
     * @param index 索引
     * @return value
     */
    @Override
    public Object listIndex(Object key, int index) {
        return redisTemplate.opsForList().index(appendKeyPrefix(key), index);
    }

    /**
     * 获取 key 所存储的 list 中指定索引的元素
     *
     * @param key key
     * @param index 索引
     * @return value
     */
    @Override
    public Object listIndex(String key, int index) {
        return listIndex((Object) key, index);
    }

    /**
     * 获取 key 所存储的 list 的长度
     *
     * @param key key
     * @return value
     */
    @Override
    public Long listSize(Object key) {
        return redisTemplate.opsForList().size(appendKeyPrefix(key));
    }

    /**
     * 获取 key 所存储的 list 的长度
     *
     * @param key key
     * @return value
     */
    @Override
    public Long listSize(String key) {
        return listSize((Object) key);
    }

    /**
     * 获取 key 所存储的 list 指定范围的元素
     *
     * @param key key
     * @param start 起始索引
     * @param end 结束索引
     * @return value
     */
    @Override
    public List<Object> listRange(Object key, int start, int end) {
        return redisTemplate.opsForList().range(appendKeyPrefix(key), start, end);
    }

    /**
     * 获取 key 所存储的 list 指定范围的元素
     *
     * @param key key
     * @param start 起始索引
     * @param end 结束索引
     * @return value
     */
    @Override
    public List<Object> listRange(String key, int start, int end) {
        return listRange((Object) key, start, end);
    }

    /**
     * 添加 key 所存储的 set 集合中的元素
     *
     * @param key key
     * @param value value
     */
    @Override
    public void setAdd(Object key, Object value) {
        redisTemplate.opsForSet().add(appendKeyPrefix(key), value);
    }

    /**
     * 添加 key 所存储的 set 集合中的元素
     *
     * @param key key
     * @param value value
     */
    @Override
    public void setAdd(String key, Object value) {
        setAdd((Object) key, value);
    }

    /**
     * 弹出 key 所存储的 set 集合中的第一个元素
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T setPop(Class<T> clazz, Object key) {
        Object value = redisTemplate.opsForSet().pop(appendKeyPrefix(key));
        if (value == null || !clazz.isAssignableFrom(value.getClass())) {
            return null;
        }
        return clazz.cast(value);
    }

    /**
     * 弹出 key 所存储的 set 集合中的第一个元素
     *
     * @param clazz 泛型的类对象
     * @param key key
     * @return value
     * @param <T> 泛型
     */
    @Override
    public <T> T setPop(Class<T> clazz, String key) {
        return setPop(clazz, (Object) key);
    }

    /**
     * 弹出 key 所存储的 set 集合中的第一个元素
     *
     * @param key key
     * @return value
     */
    @Override
    public Object setPop(Object key) {
        return redisTemplate.opsForSet().pop(appendKeyPrefix(key));
    }

    /**
     * 弹出 key 所存储的 set 集合中的第一个元素
     *
     * @param key key
     * @return value
     */
    @Override
    public Object setPop(String key) {
        return setPop((Object) key);
    }

    /**
     * 获取 key 所存储的 set 集合中的所有元素
     *
     * @param key key
     * @return value
     */
    @Override
    public Set<Object> setMembers(Object key) {
        return redisTemplate.opsForSet().members(appendKeyPrefix(key));
    }

    /**
     * 获取 key 所存储的 set 集合中的所有元素
     *
     * @param key key
     * @return value
     */
    @Override
    public Set<Object> setMembers(String key) {
        return setMembers((Object) key);
    }

    /**
     * 获取 key 所存储的 set 集合的长度
     * @param key key
     * @return value
     */
    @Override
    public Long setSize(Object key) {
        return redisTemplate.opsForSet().size(appendKeyPrefix(key));
    }

    /**
     * 获取 key 所存储的 set 集合的长度
     *
     * @param key key
     * @return value
     */
    @Override
    public Long setSize(String key) {
        return setSize((Object) key);
    }
}
